/***************************************************************************************************
*Copyright(C),2010-2016,Sumscope
*FileName	:  TableCodec.cpp
*Author	:  scofined.qi
*Version	:  1.0
*Date		:  2019/09/11
*Desc		:  //用于主要说明此程序文件完成的主要功能
*Relation :
*Others	:  //其他内容说明
*Function :  //主要函数列表，每条记录应包含函数名及功能简要说明
*History	:  //修改历史记录列表，每条修改记录应包含修改日期、修改者及修改内容简介
***************************************************************************************************/
//#include "stdafx.h"
#include "TableCodec.h"
#include "FieldCollector.h"
#include "StopCodec.h"
#include "../zstd.h"
namespace qb{
	namespace proto{

		TableCodec::TableCodec() :m_row(0), m_blank((int)0), m_lastcol(-1), m_use_key(true),
			m_zbuf_size(1024 * 40), m_zbuf(NULL), m_use_zip(true)
		{
			m_collectors.clear();
			m_page.Reset();
		}

		TableCodec::~TableCodec()
		{
			for (size_t i = 0; i < m_dicts.size(); i++) {
				if (m_dicts[i] != NULL) {
					delete m_dicts[i];
				}
			}	
			m_dicts.clear();
			for (size_t i=0; i<m_collectors.size(); i++) {
				if (m_collectors[i] != NULL) {
					delete m_collectors[i];
				}
			}
			m_collectors.clear();
			m_page.Reset();
			if (m_zbuf)delete m_zbuf;
		}
		int TableCodec::GetRow()const
		{
			return m_row;
		}
		int TableCodec::GetCol()const
		{
			return m_collectors.size();
		}
		void TableCodec::AddRow(void) {
			m_row++;
		}
		TableCodec* TableCodec::Copy()
		{
			TableCodec* table = new TableCodec();
			table->m_use_key = m_use_key;
			table->m_use_zip = m_use_zip;
			for (size_t c = 0; c < m_collectors.size(); c++)
			{
				FieldCollectorPtr source = m_collectors[c];
				FieldCollectorPtr dest = table->GetCollector(source->GetKey());
				dest->SetBitWidth(source->GetBitWidth());
				for (int r = 0; r < m_row; r++)
				{
					const VarValue& vv = source->GetValue(r);
					if (vv.type == kExpectTypeString)
						dest->AddValue(r,VarValue(AllocString(vv.str.ptr, vv.str.len), vv.str.len));
					else
						dest->AddValue(r,vv);
				}
			}
			return table;
		}
		int TableCodec::GetCollectorIndex(const std::string& key)
		{
			// 假设字段都是按照固定顺序,从上一次访问的下一个目标开始
			int start = m_lastcol+1;
			if (m_lastcol < 0 || m_lastcol >= m_collectors.size())
				start = 0;
			for (int i = 0; i < m_collectors.size(); i++)
			{
				int index = (i + start) % m_collectors.size();
				if (m_collectors[index]->GetKey() == key)
				{
					m_lastcol = index;
					return m_lastcol;
				}
			}
			return -1;
		}

		void TableCodec::InitConvertMap(std::vector<FieldKey>& vecKey)
		{
			m_key_convert_map.Init(vecKey);
		}

		FieldCollectorPtr TableCodec::GetCollector(const std::string& key, bool bConvertKey)
		{
			// 假设字段都是按照固定顺序
			int index = -1;
			FieldKey* pConvertKey = m_key_convert_map.ConvertFieldKey(key);
			if (bConvertKey && pConvertKey != NULL){
				index = GetCollectorIndex(*pConvertKey);
			}
			else{
				index = GetCollectorIndex(key);
			}
			if (index >= 0) {
				m_collectors[index]->SetRow(m_row);
				return m_collectors[index];
			}

			m_collectors.push_back(new FieldCollector(kEncodeTypeAuto, m_collectors.size(), m_row));
			m_lastcol = m_collectors.size() - 1;
			m_collectors[m_lastcol]->SetKey(pConvertKey?*pConvertKey:FieldKey(key));
			return m_collectors[m_lastcol];
		}
		FieldCollectorPtr TableCodec::FindCollector(const std::string& key, bool bConvertKey)
		{
			int index = -1;
			FieldKey* pConvertKey = m_key_convert_map.ConvertFieldKey(key);
			if (bConvertKey && pConvertKey != NULL){
				index = GetCollectorIndex(*pConvertKey);
			}
			else{
				index = GetCollectorIndex(key);
			}
			if (index >= 0)
				return m_collectors[index];
			return NULL;
		}

		qb::proto::FieldCollectorPtr TableCodec::FindCollector(int index)const
		{
			if (index >= 0 && index < m_collectors.size())
				return m_collectors[index];
			return NULL;
		}

		void TableCodec::RemoveCollector(const std::string& key)
		{
			// 测试,删除指定列
			int index = GetCollectorIndex(key);
			if (index >= 0 && index<m_collectors.size())
			{
				delete m_collectors[index];
				m_collectors.erase(m_collectors.begin() + index);
			}
		}
		NameMap TableCodec::GetNameMap()
		{
			NameMap namemap;
			for (int i = 0; i < m_collectors.size(); i++)
			{
				FieldCollectorPtr& fc = m_collectors[i];
				const FieldKey& key = fc->GetKey();
				namemap[key] = key;
			}
			return namemap;
		}
		NameMap TableCodec::ChangeNumberAsKeys()
		{
			NameMap namemap;
			for (int i = 0; i < m_collectors.size(); i++)
			{
				FieldCollectorPtr& fc = m_collectors[i];
				FieldKey newkey(i);
				namemap[fc->GetKey()] = newkey;
				fc->SetKey(newkey);
			}
			return namemap;
		}
		void TableCodec::AddField(const FieldKey& key, int row, const char* str, int len)
		{
			//BASSERT(col >= 0 && col < m_collectors.size());
			GetCollector(key)->AddValue(row,VarValue(AllocString(str, len), len));
		}
		void TableCodec::AddField(const FieldKey& key, int row, double d)
		{
			//BASSERT(col >= 0 && col < m_collectors.size());
			GetCollector(key)->AddValue(row,VarValue(d));
		}
		void TableCodec::AddField(const FieldKey& key, int row, int i)
		{
			//BASSERT(col >= 0 && col < m_collectors.size());
			GetCollector(key)->AddValue(row,VarValue(i));
		}
		void TableCodec::AddField(const FieldKey& key, int row, unsigned int i)
		{
			//BASSERT(col >= 0 && col < m_collectors.size());
			GetCollector(key)->AddValue(row,VarValue(i));
		}
		void TableCodec::AddField(const FieldKey& key, int row, i64 i)
		{
			//BASSERT(col >= 0 && col < m_collectors.size());
			GetCollector(key)->AddValue(row,VarValue(i));
		}
		void TableCodec::AddField(const FieldKey& key, int row, ui64 i)
		{
			//BASSERT(col >= 0 && col < m_collectors.size());
			GetCollector(key)->AddValue(row,VarValue(i));
		}

		void TableCodec::AddDefaults(int row)
		{
			for (CollectorArray::iterator it = m_collectors.begin(); it != m_collectors.end();++it)
			{
				(*it)->AddDefault(row);
			}
		}
		char* TableCodec::AllocString(const char* str, int len)
		{
			return const_cast<char*>(m_page.AddString(str, len));
		}

		void TableCodec::Reset()
		{
			m_page.Reset();
			m_page.Reset();
			m_collectors.clear();
			m_dicts.clear();
			m_row = 0;
			m_lastcol = -1;
		}
		bool TableCodec::EqualValues(const TableCodec& table)const
		{
			if (m_row != table.m_row)
				return false;
			if (m_collectors.size() != table.m_collectors.size())
				return false;
			for (int i = 0; i < (int)m_collectors.size();i++)
			{
				if (!m_collectors[i]->EqualValues(table.m_collectors[i]))
					return false;
			}
			return true;
		}
		int TableCodec::GetStat(FieldStatMap& stat)
		{
			// 返回key为空的个数
			int nempty = 0;
			for (CollectorArray::iterator it = m_collectors.begin(); it != m_collectors.end();++it)
			{
				FieldCollectorPtr& field = *it;
				const FieldKey& key = field->GetKey();
				FieldStatMap::iterator sit = stat.find(key);
				if (sit == stat.end())
				{
					stat[key] = FieldStat();
					sit = stat.find(key);
				}
				field->GetStat(sit->second);
			}
			return nempty;
		}
		void TableCodec::PrepareBuffer(int size)
		{
			if (m_zbuf_size < size || m_zbuf == NULL)
			{
				if (m_zbuf)
					delete[] m_zbuf;
				m_zbuf_size = ((size / 4096) + 1) * 4096;
				m_zbuf = new char[m_zbuf_size];
			}
		}
		const char* ZSTD::versionString(void)
		{
			return ZSTD_versionString();
		}
		size_t ZSTD::compress(void* dst, size_t dstCapacity,
			const void* src, size_t srcSize,
			int compressionLevel)
		{
			return ZSTD_compress(dst, dstCapacity, src, srcSize, compressionLevel);
		}
		size_t ZSTD::decompress(void* dst, size_t dstCapacity,
			const void* src, size_t compressedSize)
		{
			return ZSTD_decompress(dst, dstCapacity, src, compressedSize);
		}
		unsigned long long ZSTD::getFrameContentSize(const void *src, size_t srcSize)
		{
			return ZSTD_getDecompressedSize(src, srcSize);
		}
		size_t      ZSTD::compressBound(size_t srcSize)
		{
			return ZSTD_compressBound(srcSize);
		}
		unsigned    ZSTD::isError(size_t code)
		{
			return ZSTD_isError(code);
		}
		const char* ZSTD::getErrorName(size_t code)
		{
			return ZSTD_getErrorName(code);
		}
		int         ZSTD::minCLevel(void)
		{
			return ZSTD_minCLevel();
		}
		int         ZSTD::maxCLevel(void)
		{
			return ZSTD_maxCLevel();
		}

	}//namespace base;
}//namespace ss;
